/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
/**
 * 
 */
package robocup.component.worldmodel.particlefilter;

import java.util.Random;

import robocup.component.geometry.Vektor;
import robocup.component.infotypes.FlagInfo;

/**
 * @author werwurm
 * 
 */
public class Region {

	private Vektor origin;

	private double minDistance;

	private double maxDistance;

	private double minDirection;

	private double directionDelta;

	private Vektor helperVektor = new Vektor();

	private Random random = new Random(System.currentTimeMillis());

	/**
	 * A defined region for particles.
	 * 
	 * @param fi -
	 *            a seen flag, for which the region should be used.
	 * @param headAngle -
	 *            the headAngle, needed to define the region
	 * @param flagPosition -
	 *            the fixed position of the flag
	 */
	public Region(FlagInfo fi, double headAngle, Vektor flagPosition) {
		super();
		this.origin = flagPosition;

		this.minDistance = Math
				.log(((double) Math.rint(fi.getDistance() / 0.1) - 0.5) * 0.1);
		this.minDistance = Math.exp(((double) Math
				.rint(this.minDistance / 0.01) - 0.5) * 0.01);
		this.maxDistance = Math
				.log(((double) Math.rint(fi.getDistance() / 0.1) + 0.5) * 0.1);
		this.maxDistance = Math.exp(((double) Math
				.rint(this.maxDistance / 0.01) + 0.5) * 0.01);

		this.minDirection = 180 + fi.getDirection() + headAngle - 1;
		double maxDirection = 180 + fi.getDirection() + headAngle + 1;
		this.directionDelta = (new Vektor(1,
				(maxDirection < this.minDirection ? maxDirection + 360
						: maxDirection)
						- this.minDirection)).getAngle();
	}

	public void reinitRegionFlag(FlagInfo fi, double headAngle,
			Vektor flagPosition) {
		this.origin = flagPosition;

		this.minDistance = Math
				.log(((double) Math.rint(fi.getDistance() / 0.1) - 0.5) * 0.1);
		this.minDistance = Math.exp(((double) Math
				.rint(this.minDistance / 0.01) - 0.5) * 0.01);
		this.maxDistance = Math
				.log(((double) Math.rint(fi.getDistance() / 0.1) + 0.5) * 0.1);
		this.maxDistance = Math.exp(((double) Math
				.rint(this.maxDistance / 0.01) + 0.5) * 0.01);

		this.minDirection = 180 + fi.getDirection() + headAngle - 1;
		this.directionDelta = 2.0;
	}

	public void reinitRegionSpeed(Vektor speed, Vektor origin) {
		this.origin = origin;
		double speedHelper = speed.getLength();
		this.minDistance = speedHelper - 0.005;
		this.maxDistance = speedHelper + 0.005;

		this.minDirection = speed.getAngle() - .5;
		this.directionDelta = 1.0;
	}

	public Vektor makeRandomInsideRegion(Vektor point) {
		if (point == null)
			point = new Vektor();

		point.setLength(this.minDistance
				+ (this.maxDistance - this.minDistance)
				* this.random.nextDouble());
		point.rotate(-point.getAngle() + this.minDirection
				+ (2 * this.random.nextDouble()));
		return point.addToThis(this.origin);
	}

	public void setOrigin(Vektor origin) {
		this.origin = origin;
	}

	public double insideRegion(Vektor point) {
		this.helperVektor.x = point.x;
		this.helperVektor.y = point.y;
		this.helperVektor.subFromThis(this.origin);
		this.helperVektor.rotate(-this.minDirection);
		if (this.helperVektor.getAngle() <= this.directionDelta
				&& this.helperVektor.getAngle() >= 0
				&& this.helperVektor.getLength() >= this.minDistance
				&& this.helperVektor.getLength() <= this.maxDistance) {
			return 1.0;
		} else
			return -1;
	}
}
